package com.quanyue.haircut.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.dangdang.ddframe.rdb.sharding.api.ShardingDataSourceFactory;
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule;
import com.quanyue.auto.sharding.conf.DynamicDataSource;
import com.quanyue.auto.sharding.conf.ShardDataSourceConfig;
import com.quanyue.auto.sharding.conf.ShardDataSourceProperties;
import com.quanyue.auto.sharding.service.TableRuleService;
import com.vhuomai.mybatis.mapper.auto.AutoConfiguration;
import com.vhuomai.mybatis.mapper.page.PageInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EnableConfigurationProperties(ShardDataSourceProperties.class)
public class DatabaseConfig {
    @Autowired
    private TableRuleService tableRuleService;
    @Autowired
    private ShardDataSourceProperties properties;

    @Bean
    public DataSource dataSource() throws Exception {
        //按照目标数据源名称和目标数据源对象的映射存放在Map中
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("default", this.defaultDataSource());
        targetDataSources.put("sharding", this.sharDingDataSource());
        //采用AbstractRoutingDataSource的对象包装多数据源
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);
        //设置默认的数据源，当拿不到数据源时，使用此配置
        dataSource.setDefaultTargetDataSource(targetDataSources.get("default"));
        return dataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource());
        bean.setConfiguration(new AutoConfiguration());
        bean.setTypeAliasesPackage("com.quanyue.haircut.domain,com.quanyue.auto.wechat.domain");
        PageInterceptor pageInterceptor = new PageInterceptor();
        bean.setPlugins(new Interceptor[]{pageInterceptor});
        return bean.getObject();
    }

    @Bean
    public SqlSessionTemplate shardingSqlSessionTemplate() throws Exception  {
        return new SqlSessionTemplate(sqlSessionFactory());
    }

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource defaultDataSource() {
        return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }



    @ConfigurationProperties(prefix = "sharding.jdbc")
    public DataSource sharDingDataSource() throws Exception {
        Map<String, List<String>> map = new HashMap<>(2);
        this.createSharDingTable("qy_card", 2, map);
        this.createSharDingTable("qy_card_order", 2, map);
        List<TableRule> tableRules = tableRuleService.createTableRules(map, properties);
        ShardingRule rule = ShardDataSourceConfig.createSharDataSource(properties).shardingRule(tableRules);
        return ShardingDataSourceFactory.createDataSource(rule);
    }


    private Map<String, List<String>> createSharDingTable(String markTable, int count, Map<String, List<String>> map) {
        List list = new ArrayList();
        for (int i = 0; i < count; i++) {
            list.add(markTable + "_" + i);
        }
        map.put(markTable, list);
        return map;
    }

    @Bean
    public WallFilter wallFilter() {
        WallFilter wallFilter = new WallFilter();
        wallFilter.setConfig(wallConfig());
        return wallFilter;
    }

    @Bean
    public WallConfig wallConfig() {
        WallConfig wallConfig = new WallConfig();
        wallConfig.setMultiStatementAllow(true);
        return wallConfig;
    }
}
